/*****************************************************************************
#
#
******************************************************************************/
#include "EPD_5in83b_Z83.h"
#include "DEBUG.h"
// #include "EPD_SDCard.h"

#define DEBUG Debug

static uint8_t iLut = 0;

/******************************************************************************
function :	Software reset
parameter:
******************************************************************************/
static void EPD_5IN83B_Z83_Reset(void)
{
    // DEV_Digital_Write(EPD_RST_PIN, 1);
    // DEV_Delay_ms(10);
    DEV_Digital_Write(EPD_RST_PIN, 0);
    DEV_Delay_ms(10);
    DEV_Digital_Write(EPD_RST_PIN, 1);
    DEV_Delay_ms(10);
}

/******************************************************************************
function :	send command
parameter:
     Reg : Command register
******************************************************************************/
static void EPD_5IN83B_Z83_SendCommand(UBYTE Reg)
{
    DEV_Digital_Write(EPD_DC_PIN, 0);
    // DEV_Digital_Write(EPD_CS_PIN, 0);
    DEV_SPI_WriteByte(Reg);
    // DEV_Digital_Write(EPD_CS_PIN, 1);
}

/******************************************************************************
function :	send data
parameter:
    Data : Write data
******************************************************************************/

static void EPD_5IN83B_Z83_SendData(UBYTE Data)
{
    DEV_Digital_Write(EPD_DC_PIN, 1);
    // DEV_Digital_Write(EPD_CS_PIN, 0);
    DEV_SPI_WriteByte(Data);
    // DEV_Digital_Write(EPD_CS_PIN, 1);
}

static void EPD_5IN83B_Z83_SendData2(UBYTE *Data, UDOUBLE length)
{
    DEV_SPI_WriteByte(Data, length);
}

static void EPD_5IN83B_Z83_SendData2(UBYTE Data)
{
    // DEV_Digital_Write(EPD_DC_PIN, 1);
    // DEV_Digital_Write(EPD_CS_PIN, 0);
    DEV_SPI_WriteByte(Data);
    // DEV_Digital_Write(EPD_CS_PIN, 1);
}

/******************************************************************************
function :	Wait until the busy_pin goes LOW
parameter:
******************************************************************************/
static void EPD_5IN83B_Z83_ReadBusy(void)
{
    DEBUG("e-Paper busy\r\n");
    while (1)
    {
        if (DEV_Digital_Read(EPD_BUSY_PIN) == 1) // busy:0
            break;
        DEV_Delay_ms(10);
    }

    DEBUG("e-Paper busy release\r\n");
}

void EPD_5IN83B_Z83_ReadBusy(uint32_t ms)
{
    Debug("e-Paper busy:%d\r\n", millis());
    for (uint32_t i = 0; i < ms; i += 10)
    {
        if (DEV_Digital_Read(EPD_BUSY_PIN)) ////busy:0
        {
            Debug("e-Paper busy release:%d\r\n", millis());
            return;
        }
        if (ms > 200)
        {
#ifndef TEST
            EPD_BUSY_attachInterrupt(LOW);
#else
            DEV_Delay_ms(10);
#endif
        }
        else
            DEV_Delay_ms(10);
    }
    Debug("e-Paper busy timeout:%d\r\n", millis());
}

/******************************************************************************
function :	Initialize the e-Paper register
parameter:
******************************************************************************/
void EPD_5IN83B_Z83_Init(uint8_t lut_type)
{

    EPD_5IN83B_Z83_Reset();

    EPD_5IN83B_Z83_SendCommand(0x01); // POWER SETTING
    EPD_5IN83B_Z83_SendData(0x07);
    EPD_5IN83B_Z83_SendData(0x07); // VGH=20V,VGL=-20V
    EPD_5IN83B_Z83_SendData(0x3f); // VDH=15V
    EPD_5IN83B_Z83_SendData(0x3f); // VDL=-15V

    EPD_5IN83B_Z83_SendCommand(0x04); // POWER ON
    DEV_Delay_ms(100);
    EPD_5IN83B_Z83_ReadBusy(100); // waiting for the electronic paper IC to release the idle signal

    EPD_5IN83B_Z83_SendCommand(0X00); // PANNEL SETTING
    EPD_5IN83B_Z83_SendData(0x0F);    // KW-3f   KWR-2F	BWROTP 0f	BWOTP 1f

    EPD_5IN83B_Z83_SendCommand(0x61); // tres
    // EPD_5IN83B_Z83_SendData(0x02);    // source 648
    // EPD_5IN83B_Z83_SendData(0x88);
    // EPD_5IN83B_Z83_SendData(0x01); // gate 480
    // EPD_5IN83B_Z83_SendData(0xe0);
    EPD_5IN83B_Z83_SendData(EPD_5IN83B_Z83_WIDTH / 256); // source 648
    EPD_5IN83B_Z83_SendData(EPD_5IN83B_Z83_WIDTH % 256);
    EPD_5IN83B_Z83_SendData(EPD_5IN83B_Z83_HEIGHT / 256); // gate 480
    EPD_5IN83B_Z83_SendData(EPD_5IN83B_Z83_HEIGHT % 256);

    // EPD_5IN83B_Z83_SendCommand(0x65);
    // EPD_5IN83B_Z83_SendData(0X03);
    // EPD_5IN83B_Z83_SendData(0X80);
    // EPD_5IN83B_Z83_SendData(0X03);
    // EPD_5IN83B_Z83_SendData(0X80);

    // EPD_5IN83B_Z83_SendCommand(0X15);
    // EPD_5IN83B_Z83_SendData(0x00);

    EPD_5IN83B_Z83_SendCommand(0X50); // VCOM AND DATA INTERVAL SETTING
    // EPD_5IN83B_Z83_SendData(0x11);
    EPD_5IN83B_Z83_SendData(0x01); // white border
                                   // EPD_5IN83B_Z83_SendData(0x11);
    EPD_5IN83B_Z83_SendData(0x07);

    EPD_5IN83B_Z83_SendCommand(0X60); // TCON SETTING
    EPD_5IN83B_Z83_SendData(0x22);
}

#define VSS (0b00)
#define VH1 (0b01)
#define VSL (0b10)
#define VH2 (0b11)
#define V(a, b, c, d) (a << 6 | b << 4 | c << 2 | d)

#define W___ V(VSL, VSS, VSS, VSS)
#define R___ V(VH2, VSS, VSS, VSS)
#define B___ V(VH1, VSS, VSS, VSS)
#define _B__ V(VSS, VH1, VSS, VSS)
#define _W__ V(VSS, VSL, VSS, VSS)
#define _R__ V(VSS, VH2, VSS, VSS)
#define BW__ V(VH1, VSL, VSS, VSS)
#define RW__ V(VH2, VSL, VSS, VSS)

#define __R_ V(VSS, VSS, VH2, VSS)

#define WR__ V(VSL, VH2, VSS, VSS)

#define T1 2 // 30 // charge balance pre-phase
#define T2 1 // 5 // optional extension
#define T3 2 // 30 // color change phase (b/w)
#define T4 1 // 5 // optional extension for one color

#if 1
static const uint8_t lutc_grey8_bwr[] PROGMEM =
    {
        //  LEVEL  A  B  C  D  RP
        0, 0, 0, 0, 0, 0, // 0
        0, 0, 0, 0, 0, 0, // 1
        0, 0, 0, 0, 0, 0, // 2
        0, 0, 0, 0, 0, 0, // 3
        0, 0, 0, 0, 0, 0, // 4
        0, 0, 0, 0, 0, 0, // 5
        0, 0, 0, 0, 0, 0, // 6
        0, 0, 0, 0, 0, 0, // 7
        0, 0, 0, 0, 0, 0, // 8
        0, 0, 0, 0, 0, 0, // 9
};

static const uint8_t lutww_grey8_bwr[] PROGMEM =
    {
        //  LEVEL  A  B  C  D  RP
        0, 0, 0, 0, 0, 0, // 0
        0, 0, 0, 0, 0, 0, // 1
        0, 0, 0, 0, 0, 0, // 2
        0, 0, 0, 0, 0, 0, // 3
        0, 0, 0, 0, 0, 0, // 4
        0, 0, 0, 0, 0, 0, // 5
        0, 0, 0, 0, 0, 0, // 6
};

static const uint8_t lutkw_grey8_bwr[] PROGMEM = // red
    {
        //  LEVEL  A  B  C  D  RP
        R___, 0x0E, 0, 0, 0, 1, // 0
        0, 0, 0, 0, 0, 0,       // 1
        0, 0, 0, 0, 0, 0,       // 2
        0, 0, 0, 0, 0, 0,       // 3
        0, 0, 0, 0, 0, 0,       // 4
        0, 0, 0, 0, 0, 0,       // 5
        0, 0, 0, 0, 0, 0,       // 6
        0, 0, 0, 0, 0, 0,       // 7
        0, 0, 0, 0, 0, 0,       // 8
        0, 0, 0, 0, 0, 0,       // 9
};

static const uint8_t lutwk_grey8_bwr[] PROGMEM = // black
    {
        //  LEVEL  A  B  C  D  RP
        B___, 0x01, 0, 0, 0, 1, // 0
        0, 0, 0, 0, 0, 0,       // 1
        0, 0, 0, 0, 0, 0,       // 2
        0, 0, 0, 0, 0, 0,       // 3
        0, 0, 0, 0, 0, 0,       // 4
        0, 0, 0, 0, 0, 0,       // 5
        0, 0, 0, 0, 0, 0,       // 6
        0, 0, 0, 0, 0, 0,       // 7
        0, 0, 0, 0, 0, 0,       // 8
        0, 0, 0, 0, 0, 0,       // 9
};

static const uint8_t lutkk_grey8_bwr[] PROGMEM = // white
    {
        //  LEVEL  A  B  C  D  RP
        0, 0, 0, 0, 0, 0, // 0
        0, 0, 0, 0, 0, 0, // 1
        0, 0, 0, 0, 0, 0, // 2
        0, 0, 0, 0, 0, 0, // 3
        0, 0, 0, 0, 0, 0, // 4
        0, 0, 0, 0, 0, 0, // 5
        0, 0, 0, 0, 0, 0, // 6
        0, 0, 0, 0, 0, 0, // 7
        0, 0, 0, 0, 0, 0, // 8
        0, 0, 0, 0, 0, 0, // 9
};

static const uint8_t lutbd_grey8_bwr[] PROGMEM =
    {
        //  LEVEL  A  B  C  D  RP
        0, 0, 0, 0, 0, 0, // 0
        0, 0, 0, 0, 0, 0, // 1
        0, 0, 0, 0, 0, 0, // 2
        0, 0, 0, 0, 0, 0, // 3
        0, 0, 0, 0, 0, 0, // 4
        0, 0, 0, 0, 0, 0, // 5
        0, 0, 0, 0, 0, 0, // 6

};

static const uint8_t lut_grey8_bwr_array[7][4] = {
    //  Black TPA,RP; Red TPA,RP;
    {0x02, 0x01, 0x12, 0x01}, // ilut1
    {0x02, 0x01, 0x12, 0x01}, // ilut2
    {0x02, 0x01, 0x12, 0x01}, // ilut3
    {0x03, 0x01, 0x12, 0x01}, // ilut4
    {0x02, 0x01, 0x0E, 0x01}, // ilut5
    {0x02, 0x01, 0x0E, 0x01}, // ilut6
    {0x03, 0x01, 0x12, 0x01}, // ilut7
};

#endif

#if 0
static const uint8_t  EPD_5IN83B_Z83_lut_20_LUTC_partial[42] PROGMEM =
{
  0x00, T1, T2, T3, T4, 1,
  //0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

static const uint8_t  EPD_5IN83B_Z83_lut_21_LUTWW_partial[42] PROGMEM =
{ // 10 w
  0x00, T1, T2, T3, T4, 1,
  //0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

static const uint8_t  EPD_5IN83B_Z83_lut_22_LUTKW_partial[42] PROGMEM =
{ // 10 w
//   0x5A, T1, T2, T3, T4, 1,
      0x5A,2,1,3,1,1,
  //0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

static const uint8_t  EPD_5IN83B_Z83_lut_23_LUTWK_partial[42] PROGMEM =
{ // 01 b
//   0xA5, T1, T2, T3, T4, 1,
    0xA5,2,1,2,1,1,
  //0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

static const uint8_t  EPD_5IN83B_Z83_lut_24_LUTKK_partial[42] PROGMEM =
{ // 01 b
  0x00, T1, T2, T3, T4, 1,
  //0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

static const uint8_t EPD_5IN83B_Z83_lut_25_LUTBD_partial[42] PROGMEM =
{
  0x00, T1, T2, T3, T4, 1,
  //0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
#endif

// static void EPD_5IN83B_Z83_Grey_Lut()
// {
//     EPD_5IN83B_Z83_SendCommand(0x20);
//     for (int i = 0; i < sizeof(EPD_5IN83B_Z83_lut_20_LUTC_partial); i++)
//     {
//         EPD_5IN83B_Z83_SendData(EPD_5IN83B_Z83_lut_20_LUTC_partial[i]);
//     }

//     EPD_5IN83B_Z83_SendCommand(0x21);
//     for (int i = 0; i < sizeof(EPD_5IN83B_Z83_lut_21_LUTWW_partial); i++)
//     {
//         EPD_5IN83B_Z83_SendData(EPD_5IN83B_Z83_lut_21_LUTWW_partial[i]);
//     }

//     EPD_5IN83B_Z83_SendCommand(0x22);
//     for (int i = 0; i < sizeof(EPD_5IN83B_Z83_lut_22_LUTKW_partial); i++)
//     {
//         EPD_5IN83B_Z83_SendData(EPD_5IN83B_Z83_lut_22_LUTKW_partial[i]);
//     }

//     EPD_5IN83B_Z83_SendCommand(0x23);
//     for (int i = 0; i < sizeof(EPD_5IN83B_Z83_lut_23_LUTWK_partial); i++)
//     {
//         EPD_5IN83B_Z83_SendData(EPD_5IN83B_Z83_lut_23_LUTWK_partial[i]);
//     }

//     EPD_5IN83B_Z83_SendCommand(0x24);
//     for (int i = 0; i < sizeof(EPD_5IN83B_Z83_lut_24_LUTKK_partial); i++)
//     {
//         EPD_5IN83B_Z83_SendData(EPD_5IN83B_Z83_lut_24_LUTKK_partial[i]);
//     }

//     EPD_5IN83B_Z83_SendCommand(0x25);
//     for (int i = 0; i < sizeof(EPD_5IN83B_Z83_lut_25_LUTBD_partial); i++)
//     {
//         EPD_5IN83B_Z83_SendData(EPD_5IN83B_Z83_lut_25_LUTBD_partial[i]);
//     }

//     //   EPD_5IN83B_Z83_SendCommand(0x20);
//     //   DEV_Digital_Write(EPD_DC_PIN, 1);
//     //   EPD_5IN83B_Z83_SendData2((uint8_t *)EPD_5IN83B_Z83_lut_20_LUTC_partial, sizeof(EPD_5IN83B_Z83_lut_20_LUTC_partial));
//     //   EPD_5IN83B_Z83_SendCommand(0x21);
//     //   DEV_Digital_Write(EPD_DC_PIN, 1);
//     //   EPD_5IN83B_Z83_SendData2((uint8_t *)EPD_5IN83B_Z83_lut_21_LUTWW_partial, sizeof(EPD_5IN83B_Z83_lut_21_LUTWW_partial));
//     //   EPD_5IN83B_Z83_SendCommand(0x22);
//     //   DEV_Digital_Write(EPD_DC_PIN, 1);
//     //   EPD_5IN83B_Z83_SendData2((uint8_t *)EPD_5IN83B_Z83_lut_22_LUTKW_partial, sizeof(EPD_5IN83B_Z83_lut_22_LUTKW_partial));
//     //   EPD_5IN83B_Z83_SendCommand(0x23);
//     //   DEV_Digital_Write(EPD_DC_PIN, 1);
//     //   EPD_5IN83B_Z83_SendData2((uint8_t *)EPD_5IN83B_Z83_lut_23_LUTWK_partial, sizeof(EPD_5IN83B_Z83_lut_23_LUTWK_partial));
//     //   EPD_5IN83B_Z83_SendCommand(0x24);
//     //   DEV_Digital_Write(EPD_DC_PIN, 1);
//     //   EPD_5IN83B_Z83_SendData2((uint8_t *)EPD_5IN83B_Z83_lut_24_LUTKK_partial, sizeof(EPD_5IN83B_Z83_lut_24_LUTKK_partial));
//     //   EPD_5IN83B_Z83_SendCommand(0x25);
//     //   DEV_Digital_Write(EPD_DC_PIN, 1);
//     //   EPD_5IN83B_Z83_SendData2((uint8_t *)EPD_5IN83B_Z83_lut_25_LUTBD_partial, sizeof(EPD_5IN83B_Z83_lut_25_LUTBD_partial));
// }

static void EPD_5IN83B_Z83_Grey_Lut(const uint8_t *LUTC, uint8_t LUTC_SIZE, const uint8_t *LUTWW, uint8_t LUTWW_SIZE, const uint8_t *LUTKW, uint8_t LUTKW_SIZE, const uint8_t *LUTWK, uint8_t LUTWK_SIZE, const uint8_t *LUTKK, uint8_t LUTKK_SIZE, const uint8_t *LUTBD, uint8_t LUTBD_SIZE)
{
    EPD_5IN83B_Z83_SendCommand(0x20);
    for (int i = 0; i < LUTC_SIZE; i++)
    {
        EPD_5IN83B_Z83_SendData(LUTC[i]);
    }

    EPD_5IN83B_Z83_SendCommand(0x21);
    for (int i = 0; i < LUTWW_SIZE; i++)
    {
        EPD_5IN83B_Z83_SendData(LUTWW[i]);
    }

    EPD_5IN83B_Z83_SendCommand(0x22);
    for (int i = 0; i < LUTKW_SIZE; i++)
    {
        EPD_5IN83B_Z83_SendData(LUTKW[i]);
    }

    EPD_5IN83B_Z83_SendCommand(0x23);
    for (int i = 0; i < LUTWK_SIZE; i++)
    {
        EPD_5IN83B_Z83_SendData(LUTWK[i]);
    }

    EPD_5IN83B_Z83_SendCommand(0x24);
    for (int i = 0; i < LUTKK_SIZE; i++)
    {
        EPD_5IN83B_Z83_SendData(LUTKK[i]);
    }

    EPD_5IN83B_Z83_SendCommand(0x25);
    for (int i = 0; i < LUTBD_SIZE; i++)
    {
        EPD_5IN83B_Z83_SendData(LUTBD[i]);
    }
}

void EPD_5IN83B_Z83_SetPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
{
    uint16_t xe = (x + w - 1) | 0x0007; // byte boundary inclusive (last byte)
    uint16_t ye = y + h - 1;
    x &= 0xFFF8;                      // byte boundary
    xe |= 0x0007;                     // byte boundary
    EPD_5IN83B_Z83_SendCommand(0x90); // partial window
    EPD_5IN83B_Z83_SendData(x / 256);
    EPD_5IN83B_Z83_SendData(x % 256);
    EPD_5IN83B_Z83_SendData(xe / 256);
    EPD_5IN83B_Z83_SendData(xe % 256);
    EPD_5IN83B_Z83_SendData(y / 256);
    EPD_5IN83B_Z83_SendData(y % 256);
    EPD_5IN83B_Z83_SendData(ye / 256);
    EPD_5IN83B_Z83_SendData(ye % 256);
    EPD_5IN83B_Z83_SendData(0x01);
}

/******************************************************************************
function :	Initialize the e-Paper register
parameter:
******************************************************************************/
void EPD_5IN83B_Z83_Init_Fast(uint8_t lut_type)
{

    EPD_5IN83B_Z83_Reset();

    EPD_5IN83B_Z83_SendCommand(0x01); // POWER SETTING
    EPD_5IN83B_Z83_SendData(0x07);
    EPD_5IN83B_Z83_SendData(0x07); // VGH=20V,VGL=-20V
    EPD_5IN83B_Z83_SendData(0x3f); // VDH=15V
    EPD_5IN83B_Z83_SendData(0x3f); // VDL=-15V
    EPD_5IN83B_Z83_SendData(0x03); // VH2=3V
    // EPD_5IN83B_Z83_SendData(0x08); // VH2=4V
    // EPD_5IN83B_Z83_SendData(0x0D); // VH2=5V

    EPD_5IN83B_Z83_SendCommand(0x04); // POWER ON
    DEV_Delay_ms(100);
    EPD_5IN83B_Z83_ReadBusy(100); // waiting for the electronic paper IC to release the idle signal

    // if (lut_type == EPD_5IN83B_Z83_Grey_Bwr8)
    {
        uint8_t lutwk_temp[60]; // black
        memcpy(lutwk_temp, lutwk_grey8_bwr, 60);
        uint8_t lutkw_temp[60]; // red
        memcpy(lutkw_temp, lutkw_grey8_bwr, 60);

        if (iLut > 0 && iLut < 8)
        {
            lutwk_temp[1] = lut_grey8_bwr_array[iLut - 1][0];
            lutwk_temp[5] = lut_grey8_bwr_array[iLut - 1][1];
            lutkw_temp[1] = lut_grey8_bwr_array[iLut - 1][2];
            lutkw_temp[5] = lut_grey8_bwr_array[iLut - 1][3];
        }
        EPD_5IN83B_Z83_Grey_Lut(lutc_grey8_bwr, sizeof(lutc_grey8_bwr), lutww_grey8_bwr, sizeof(lutww_grey8_bwr), lutkw_temp, sizeof(lutkw_temp), lutwk_temp, sizeof(lutwk_temp), lutkk_grey8_bwr, sizeof(lutkk_grey8_bwr), lutbd_grey8_bwr, sizeof(lutbd_grey8_bwr));
    }

    // EPD_5IN83B_Z83_Grey_Lut(lutc_grey8_bwr,sizeof(lutc_grey8_bwr),lutww_grey8_bwr,sizeof(lutww_grey8_bwr),lutkw_grey8_bwr,sizeof(lutkw_grey8_bwr),lutwk_grey8_bwr,sizeof(lutwk_grey8_bwr),lutkk_grey8_bwr,sizeof(lutkk_grey8_bwr),lutbd_grey8_bwr,sizeof(lutbd_grey8_bwr));
    EPD_5IN83B_Z83_SendCommand(0X00); // PANNEL SETTING
    // EPD_5IN83B_Z83_SendData(0x3F);    // KW-3f   KWR-2F	BWROTP 0f	BWOTP 1f
    EPD_5IN83B_Z83_SendData(0x2F); // KW-3f   KWR-2F	BWROTP 0f	BWOTP 1f

    EPD_5IN83B_Z83_SendCommand(0x61);                    // tres
    EPD_5IN83B_Z83_SendData(EPD_5IN83B_Z83_WIDTH / 256); // source 648
    EPD_5IN83B_Z83_SendData(EPD_5IN83B_Z83_WIDTH % 256);
    EPD_5IN83B_Z83_SendData(EPD_5IN83B_Z83_HEIGHT / 256); // gate 480
    EPD_5IN83B_Z83_SendData(EPD_5IN83B_Z83_HEIGHT % 256);

    // EPD_5IN83B_Z83_SendCommand(0X15);
    // EPD_5IN83B_Z83_SendData(0x00);

    EPD_5IN83B_Z83_SendCommand(0xE0);
    EPD_5IN83B_Z83_SendData(0x02);
    EPD_5IN83B_Z83_SendCommand(0xE5);
    EPD_5IN83B_Z83_SendData(0x6E);
    // EPD_5IN83B_Z83_SendData(0x5A);

    EPD_5IN83B_Z83_SendCommand(0x82);
    EPD_5IN83B_Z83_SendData(0x31);
    EPD_5IN83B_Z83_SendCommand(0X50); // VCOM AND DATA INTERVAL SETTING
                                      // EPD_5IN83B_Z83_SendData(0x11);
                                      // EPD_5IN83B_Z83_SendData(0xA9); //
                                      // EPD_5IN83B_Z83_SendData(0x39);    //
                                      // EPD_5IN83B_Z83_SendData(0x89);    //
    EPD_5IN83B_Z83_SendData(0x81);    //
    //    EPD_5IN83B_Z83_SendData(0x01);    //
    EPD_5IN83B_Z83_SendData(0x07);

    EPD_5IN83B_Z83_SendCommand(0X60); // TCON SETTING
    EPD_5IN83B_Z83_SendData(0x22);

    // EPD_5IN83B_Z83_SendCommand(0x91);
    // EPD_5IN83B_Z83_SetPartialRamArea(0, 0, EPD_5IN83B_Z83_WIDTH, EPD_5IN83B_Z83_HEIGHT);
    //     EPD_5IN83B_Z83_SendCommand(0x92);
}

/******************************************************************************
function :	Clear screen
parameter:
******************************************************************************/
void EPD_5IN83B_Z83_Clear(void)
{
    UDOUBLE Width, Height;
    Width = (EPD_5IN83B_Z83_WIDTH % 8 == 0) ? (EPD_5IN83B_Z83_WIDTH / 8) : (EPD_5IN83B_Z83_WIDTH / 8 + 1);
    Height = EPD_5IN83B_Z83_HEIGHT;

    unsigned int i;
    EPD_5IN83B_Z83_SendCommand(0x10); // write RAM for black(0)/white (1)
    DEV_Digital_Write(EPD_DC_PIN, 1);
    for (i = 0; i < Width * Height; i++)
    {
        // EPD_5IN83B_Z83_SendData(0xFF);
        EPD_5IN83B_Z83_SendData2(0x00);
    }
    EPD_5IN83B_Z83_SendCommand(0x13); // write RAM for black(0)/white (1)
    DEV_Digital_Write(EPD_DC_PIN, 1);
    for (i = 0; i < Width * Height; i++)
    {
        // EPD_5IN83B_Z83_SendData(0x00);
        EPD_5IN83B_Z83_SendData2(0x00);
    }
    EPD_5IN83B_Z83_TurnOnDisplay(EPD_5IN83B_FULL);
}

/******************************************************************************
function :	Sends the image buffer in RAM to e-Paper and displays
parameter:
******************************************************************************/
void EPD_5IN83B_Z83_Display(unsigned char *BW_Image, unsigned char *R_Image)
{
    UDOUBLE Width, Height;
    Width = (EPD_5IN83B_Z83_WIDTH % 8 == 0) ? (EPD_5IN83B_Z83_WIDTH / 8) : (EPD_5IN83B_Z83_WIDTH / 8 + 1);
    Height = EPD_5IN83B_Z83_HEIGHT;

    // send black data

    EPD_5IN83B_Z83_SendCommand(0x10);
    DEV_Digital_Write(EPD_DC_PIN, 1);
    EPD_5IN83B_Z83_SendData2(BW_Image, Width * Height);

    EPD_5IN83B_Z83_SendCommand(0x13);
    DEV_Digital_Write(EPD_DC_PIN, 1);
    EPD_5IN83B_Z83_SendData2(R_Image, Width * Height);

    EPD_5IN83B_Z83_TurnOnDisplay(EPD_5IN83B_FULL);
}

/******************************************************************************
function :	Enter sleep mode
parameter:
******************************************************************************/
void EPD_5IN83B_Z83_Sleep(void)
{
    EPD_5IN83B_Z83_SendCommand(0x02); // POWER_OFF
    EPD_5IN83B_Z83_ReadBusy(100);
    EPD_5IN83B_Z83_SendCommand(0x07); // DEEP_SLEEP
    EPD_5IN83B_Z83_SendData(0XA5);
}

/******************************************************************************
function :	Turn On Display
parameter:
******************************************************************************/
// void EPD_5IN83B_Z83_TurnOnDisplay(void)
// {
//     EPD_5IN83B_Z83_SendCommand(0x22); // Display Update Control
//     EPD_5IN83B_Z83_SendData(0xF7);
//     EPD_5IN83B_Z83_SendCommand(0x20); // Activate Display Update Sequence
//     EPD_5IN83B_Z83_ReadBusy(15 * 1000);
// }

void EPD_5IN83B_Z83_TurnOnDisplay(uint8_t part)
{
    EPD_5IN83B_Z83_SendCommand(0x12); // display refresh
    EPD_5IN83B_Z83_ReadBusy(30 * 1000);
}

/******************************************************************************
function :	Sends the image buffer in RAM to e-Paper and displays
parameter:  color:black,0;red,1;*data;index;length
******************************************************************************/
void EPD_5IN83B_Z83_Data_Write(UBYTE color, UBYTE *Image_Data, UDOUBLE index, UDOUBLE length)
{
    if (index == 0)
    // if (1)
    {
        if (color == 0)
        {
            // EPD_5IN83B_Z83_SendCommand(0x91);
            // EPD_5IN83B_Z83_SetPartialRamArea(0, 0, EPD_5IN83B_Z83_WIDTH, EPD_5IN83B_Z83_HEIGHT);
            EPD_5IN83B_Z83_SendCommand(0x10);
        }
        else if (color == 1)
        {
            // EPD_5IN83B_Z83_SendCommand(0x92);
            // EPD_5IN83B_Z83_SendCommand(0x91);
            // EPD_5IN83B_Z83_SetPartialRamArea(0, 0, EPD_5IN83B_Z83_WIDTH, EPD_5IN83B_Z83_HEIGHT);
            EPD_5IN83B_Z83_SendCommand(0x13);
        }
        DEV_Digital_Write(EPD_DC_PIN, 1);
    }

    if (color == 0)
    {
        for (int i = 0; i < length; i++)
        {
            Image_Data[i] = ~Image_Data[i];
        }
    }

    UDOUBLE Width, Height;
    Width = (EPD_5IN83B_Z83_WIDTH % 8 == 0) ? (EPD_5IN83B_Z83_WIDTH / 8) : (EPD_5IN83B_Z83_WIDTH / 8 + 1);
    Height = EPD_5IN83B_Z83_HEIGHT;

    // if(length==(Width*Height))
    // {
    //     for (UDOUBLE j = 0; j < Height; j++)
    //     {
    //         for (UDOUBLE i = 0; i < Width; i++)
    //         {
    //             EPD_5IN83B_Z83_SendData(Image_Data[i + (Height-j) * Width]);
    //         }
    //     }

    // }
    // else{
#ifdef EPD_SPI_ENABLE
    EPD_5IN83B_Z83_SendData2(Image_Data, length);
#else
    for (UDOUBLE i = 0; i < length; i++)
    {
        if (color == 0)
        {
            // DEV_Digital_Write(EPD_DC_PIN, 1);
            // DEV_Digital_Write(EPD_CS_PIN, 0);
            EPD_5IN83B_Z83_SendData2(Image_Data[i]);
            // DEV_Digital_Write(EPD_CS_PIN, 1);
        }
        else if (color == 1)
        {
            // DEV_Digital_Write(EPD_DC_PIN, 1);
            // DEV_Digital_Write(EPD_CS_PIN, 0);
            EPD_5IN83B_Z83_SendData2(Image_Data[i]);
            // DEV_Digital_Write(EPD_CS_PIN, 1);
        }
    }
#endif
    // }
}

void EPD_5IN83B_Z83_setDepth(uint8_t i)
{
    iLut = i ? (i > 15 ? 15 : i) : 15;
}

#if 0
int8_t EPD_5IN83B_Z83_ReadTemp()
{
    int8_t rc=0;

    // EPD_SSD_SendCommand(0x12); // soft reset
    // EPD_SSD_WaitBusy(100);
    // EPD_5IN83B_Z83_Reset();

    // EPD_5IN83B_Z83_ReadBusy(100);
    EPD_5IN83B_Z83_SendCommand(0x12); // SWRESET
    // EPD_5IN83B_Z83_ReadBusy(1000);
    DEV_Delay_us(200);

    // Border Waveform
    EPD_5IN83B_Z83_SendCommand(0x3C);
    EPD_5IN83B_Z83_SendData(0x05);

    // Temperature sensor control
    EPD_5IN83B_Z83_SendCommand(0x18);
    EPD_5IN83B_Z83_SendData(0x80); // 80: internal sensor 48: external sensor

    // Display update control
    EPD_5IN83B_Z83_SendCommand(0x22);
    EPD_5IN83B_Z83_SendData(0xb1); // full: 0xf7

    // Master Activation
    EPD_5IN83B_Z83_SendCommand(0x20);
    // EPD_SSD_WaitBusy(100);
    EPD_5IN83B_Z83_ReadBusy();

    // read temperature
    EPD_5IN83B_Z83_SendCommand(0x1b);
    rc = EPD_SSD_ReadData();

    return rc;
}
#endif
